(function($) {
    // DROPDOWN CLASS DEFINITION

    var backdrop = '.dropdown-backdrop';
    var toggle = '[data-toggle=dropdown]';
    var Dropdown = function(element) {
        var $el = $(element).on('click.bs.dropdown', this.toggle);
    };

    Dropdown.prototype.toggle = function(e) {
        var $this = $(this);

        if ($this.is('.disabled, :disabled')) return;

        var $parent = getParent($this);
        var isActive = $parent.hasClass('open');
        $parent.find(".dropdown-menu a").one("click", function() {
            var val = $(this).html(),
                value = val + '<span class="caret"></span>';
            $this.html(value).data("value", val);
        });

        clearMenus();

        if (!isActive) {
            if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
                // if mobile we we use a backdrop because click events don't delegate
                $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
            }

            $parent.trigger(e = $.Event('show.bs.dropdown'));

            if (e.isDefaultPrevented()) return;

            $parent.toggleClass('open')
                .trigger('shown.bs.dropdown');

            $this.focus()
        }

        return false
    };

    Dropdown.prototype.keydown = function(e) {
        if (!/(38|40|27)/.test(e.keyCode)) return;

        var $this = $(this);

        e.preventDefault();
        e.stopPropagation();

        if ($this.is('.disabled, :disabled')) return;

        var $parent = getParent($this);
        var isActive = $parent.hasClass('open');

        if (!isActive || (isActive && e.keyCode == 27)) {
            if (e.which == 27) $parent.find(toggle).focus();
            return $this.click();
        }

        var $items = $('[role=menu] li:not(.divider):visible a', $parent);

        if (!$items.length) return;

        var index = $items.index($items.filter(':focus'));

        if (e.keyCode == 38 && index > 0) index--; // up
        if (e.keyCode == 40 && index < $items.length - 1) index++; // down
        if (!~index) index = 0;

        $items.eq(index).focus()
    };

    function clearMenus() {
        $(backdrop).remove();
        $(toggle).each(function(e) {
            var $parent = getParent($(this));
            if (!$parent.hasClass('open')) return;
            $parent.trigger(e = $.Event('hide.bs.dropdown'));
            if (e.isDefaultPrevented()) return;
            $parent.removeClass('open').trigger('hidden.bs.dropdown');
        })
    }

    function getParent($this) {
        var selector = $this.attr('data-target');

        if (!selector) {
            selector = $this.attr('href');
            selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, ''); //strip for ie7
        }

        var $parent = selector && $(selector);

        return $parent && $parent.length ? $parent : $this.parent()
    }


    // DROPDOWN PLUGIN DEFINITION
    // ==========================

    var old = $.fn.dropdown;

    $.fn.dropdown = function(option) {
        return this.each(function() {
            var $this = $(this);
            var data = $this.data('dropdown');

            if (!data) $this.data('dropdown', (data = new Dropdown(this)));
            if (typeof option == 'string') data[option].call($this)
        })
    };

    $.fn.dropdown.Constructor = Dropdown;


    // DROPDOWN NO CONFLICT
    // ====================

    $.fn.dropdown.noConflict = function() {
        $.fn.dropdown = old;
        return this
    };


    // APPLY TO STANDARD DROPDOWN ELEMENTS
    // ===================================

    $(document)
        .on('click.bs.dropdown.data-api', clearMenus)
        .on('click.bs.dropdown.data-api', '.dropdown form', function(e) {
            e.stopPropagation();
        })
        .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
        .on('keydown.bs.dropdown.data-api', toggle + ', [role=menu]', Dropdown.prototype.keydown);

})(window.jQuery);